Skip to content

feat(tg-11): epistemic types — Epi[k, ρ, τ], non-factive by construction - #98

Merged
hyperpolymath merged 1 commit into
mainfrom
feat/epistemic-types
Jul 29, 2026
Merged

hyperpolymath merged 1 commit into
mainfrom
feat/epistemic-types

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Wires hyperpolymath/epistemic-types into the mechanised core, following the route TG-10 took for echo. Lean 0 errors, sorry/axiom gate clean.

The commitment: a warrant is not knowledge

Epi[κ, ρ, τ] — at standpoint κ, evidence of type ρ purporting to support a claim of type τ. The claim type appears in the type and no elimination rule delivers it. evidence is the sole projection, and it yields ρ.

That mirrors upstream precisely:

  • Warrant.agda gives the record only an Evidence field — deliberately not Evidence → A, because that "would make every warrant factive" — and puts extraction in a separate SoundWarrant.
  • Base.agda splits FactiveModality (with reflect : E κ A → A) from BeliefModality (without), rather than treating belief as knowledge with a missing proof.

The absence here is that same design choice, mechanised.

Six capstones

Theorem What it establishes
epi_evidence_recovers evidence ∘ warrant returns the token
epi_claim_is_opaque two warrants, same evidence, different claims, observationally identical
epi_only_yields_evidence from Epi[κ,ρ,τ] the only elimination is at ρ
epi_distinguishes_standpoints κ₁ ≠ κ₂ gives genuinely different types
epi_roundtrip_typed type safety of intro + projection
epi_over_echo_typed Epi[κ, Echo[ρ,τ], σ] — the modalities nest

epi_claim_is_opaque is the exact dual of echo_distinguishes_collapsed: echo reveals what close forgot; a warrant withholds what it purports. Holding evidence is not holding the fact.

epi_over_echo_typed mirrors EpistemicEcho in EchoBridge.agda, which is explicit that these are different modalities — echo grades irrecoverability, epi indexes standpoints — and that they compose without collapsing.

Metatheory extended, not weakened

Progress, Preservation, Determinism, TypeSafety, infer_sound, infer_complete all cover the new fragment, plus a new canonical_epi lemma.

Worth noting where non-factivity actually lands: in preservation, the evidenceVal case inverts tEvidence then tEpiVal and returns the token's typing (he), never the claim's (hc). Non-factivity is discharged by the type system rather than asserted in a comment.

Both engines

OCaml mirrors it — TEpi former, Warrant/EpiVal/Evidence, VEpi runtime value, typing and evaluation. TG-3 extended with 4 pins (including that evidence yields the evidence type, never the claim); differential regenerated and kernel-checked: 496 obligations, 0 errors. TG-3 self-check 1008 → 1012.

⚠ Registered honestly — A-TG-11.1

What the simply-typed shadow does not model:

  • standpoints are Nat, not an arbitrary index set K;
  • upstream's LawfulModality functor laws, FactiveModality.reflect and ReturnModality.return are omitted (all opt-in there);
  • the real gap — the claim is carried in the value rather than erased, because erasing it would break uniqueness of typing in a system without quantities.

A QTT treatment (quantity 0 on the claim) would be the faithful version — which is the same conclusion the linear/affine discussion reached independently.

Tests

6 typecheck cases, including two negatives: that evidence never returns the claim type when the two differ, and that evidence of a non-warrant is rejected. Typecheck suite 129 → 135; all suites green; corpus and RSR gates pass.

🤖 Generated with Claude Code

…ruction

Wires hyperpolymath/epistemic-types into the mechanised core, following the
route TG-10 took for echo. Lean 0 errors, sorry/axiom gate clean.

## The commitment: a warrant is not knowledge

`Epi[k, rho, tau]` = at standpoint k, evidence of type rho purporting to
support a claim of type tau. The claim type appears in the type and NO
elimination rule delivers it. `evidence` is the sole projection and yields
rho.

That mirrors upstream exactly. `Warrant.agda` gives the record only an
`Evidence` field — deliberately not `Evidence -> A`, because that "would make
every warrant factive" — and puts extraction in a separate `SoundWarrant`.
`Base.agda` likewise splits `FactiveModality` (with `reflect`) from
`BeliefModality` (without), rather than treating belief as knowledge with a
missing proof. The absence here is that same choice, mechanised.

## Six capstones

  epi_evidence_recovers        evidence . warrant returns the token
  epi_claim_is_opaque          two warrants, same evidence, DIFFERENT claims
                               are observationally identical — the dual of
                               echo_distinguishes_collapsed: echo REVEALS what
                               close forgot, a warrant WITHHOLDS what it
                               purports
  epi_only_yields_evidence     from Epi[k,rho,tau] the only elimination is rho
  epi_distinguishes_standpoints  k1 /= k2 gives different types
  epi_roundtrip_typed          type safety of intro + projection
  epi_over_echo_typed          Epi[k, Echo[rho,tau], sigma] — the two modalities
                               NEST; mirrors EpistemicEcho in EchoBridge.agda,
                               which is explicit that echo grades
                               irrecoverability while epi indexes standpoints

## Metatheory extended, not weakened

Progress, Preservation, Determinism, TypeSafety, infer_sound and
infer_complete all cover the new fragment. New `canonical_epi` lemma. In
preservation, the `evidenceVal` case inverts tEvidence then tEpiVal and
returns the TOKEN's typing, never the claim's — non-factivity discharged by
the type system rather than asserted.

## Both engines

OCaml mirrors it: `TEpi` former, `Warrant`/`EpiVal`/`Evidence` constructors,
`VEpi` runtime value, typing and evaluation. TG-3 extended with 4 pins
(including that `evidence` yields the evidence type, never the claim);
differential regenerated and kernel-checked — 496 obligations, 0 errors.
TG-3 self-check 1008 -> 1012.

## Registered honestly

TG-11 in PROOF-NEEDS.md; assumption A-TG-11.1 records what the simply-typed
shadow does NOT model: standpoints are Nat rather than an arbitrary index set,
the upstream functor laws / reflect / return are omitted (all opt-in there),
and — the real gap — the claim is CARRIED rather than erased, because erasing
it would break uniqueness of typing in a system without quantities. A QTT
treatment (quantity 0 on the claim) would be the faithful version.

Tests: 6 typecheck cases including two negatives — that evidence never returns
the claim type, and that `evidence` of a non-warrant is rejected. Typecheck
suite 129 -> 135; all suites green.

Co-Authored-By: Claude Opus 5 <[email protected]>
@gitar-bot

gitar-bot Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

Note

Automatic reviews are paused because your trial's included automatic processing has been used for this period. Upgrade now, or comment "Gitar review" to run a review anytime.
Learn more

Code Review ✅ Approved

Integrates non-factive epistemic types into the mechanised core and OCaml engine, complete with six capstones and extended metatheory. No issues found.

Auto-approved and auto-merge armed: No blocking issues found.
Please see Auto-approve Docs for details on setting custom approval criteria. — merges when pipeline and required approvals pass.

Options

Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@gitar-bot

gitar-bot Bot commented Jul 29, 2026

Copy link
Copy Markdown

⚠️ Gitar auto-approved this PR but could not enable auto-merge: auto-merge is disabled for this repository — enable "Allow auto-merge" in the repository settings.

@gitar-bot gitar-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gitar has auto-approved this PR and enabled auto-merge (configure)

@gitar-bot gitar-bot Bot added the gitar-approved Added by Gitar label Jul 29, 2026
@hyperpolymath
hyperpolymath merged commit cf56397 into main Jul 29, 2026
22 checks passed
@hyperpolymath
hyperpolymath deleted the feat/epistemic-types branch July 29, 2026 05:49
hyperpolymath added a commit that referenced this pull request Jul 29, 2026
…ent-order bug (#99)

TG-11 (#98) landed the type former, typing, evaluation and six proofs —
but there was **no way to write one**. Zero occurrences of the
constructors in `lexer.mll` or `parser.mly`, against 4 for echo. Fully
implemented and unreachable.

## Surface syntax

```tangle
def w     = warrant[0](42, braid[s1, s2])   -- at standpoint 0
def token = evidence(w)                      -- the ONLY elimination
```

The standpoint is bracketed because it's an *index*, not an operand —
the same reading as a braid generator's subscript. No grammar conflicts.

**Non-factivity reaches the syntax.** There is deliberately no keyword
extracting the claim: `claim(w)` parses as an ordinary call to an
undefined function, never as a language form. A test pins that
distinction — if a `Claim` form ever appears, it contradicts
`epi_only_yields_evidence`.

## A *second* copy of the statement-order bug

Writing the first epistemic program surfaced it immediately:

```
def w   = warrant[0](42, braid[s1])
def tok = evidence(w)
→ In definition 'tok': evidence requires an Epi[k, rho, tau], got Word[0]
```

That `Word[0]` is the pass-1a **placeholder** — `tok` was being checked
*before* `w` was refined. Same root cause as #95 (`stmts := prog @
!stmts` then `List.rev` on the flattened list), but in a **second
copy**, in `lib/check.ml`.

**That copy feeds `tanglec --check` and the LSP.** Both have been
analysing programs with their statements reversed.

And it was never epistemic-specific:

```
def e = echoClose(braid[s1])
def r = residue(e)
→ residue requires Echo[_, _], got Word[0]
```

**Any cross-definition reference to a non-`Word` type was mis-typed.**
Echo has been broken this way for as long as the recovering path has
existed.

The test suites missed *both* copies for the same reason: they call
`Parser.program` directly and never exercise the recovering path.

## Tests

**Parser** — warrant with bracketed standpoint; evidence; TG-4
round-trip; the no-claim-form guard.
**Check** — three cross-definition cases (plain, echo, epistemic), all
of which would have failed before this.

## Example

`examples/epistemic.tangle`, wired into the corpus gate's must-run set —
warrants at three standpoints, evidence recovery, and the echo
composition `residue(evidence(we))`. All assertions pass.

It also documents *why* the claim is unreachable: if it were
extractable, anything anyone attested would become true by fiat —
precisely the bug you don't want in a provenance system.

All gates green: Lean 0 errors, full suite, corpus, RSR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gitar-approved Added by Gitar

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant